import axios from 'axios';
import crypto from 'crypto';
import pool from './db';
import { RowDataPacket, ResultSetHeader } from 'mysql2';

// 阿里云短信服务配置
interface SmsConfig {
  accessKeyId: string;
  accessKeySecret: string;
  signName: string;
  templateCode: {
    registration: string;
    passwordReset: string;
  };
  endpoint: string;
}

// 验证码目的类型
export type VerificationPurpose = 'registration' | 'password_reset';

// 验证码记录
export interface VerificationCode {
  id?: number;
  phone: string;
  code: string;
  purpose: VerificationPurpose;
  created_at?: Date;
  expires_at: Date;
  is_used: boolean;
}

// 从环境变量获取配置
const smsConfig: SmsConfig = {
  accessKeyId: process.env.ALIYUN_SMS_ACCESS_KEY_ID || '',
  accessKeySecret: process.env.ALIYUN_SMS_ACCESS_KEY_SECRET || '',
  signName: process.env.ALIYUN_SMS_SIGN_NAME || '校友宝',
  templateCode: {
    registration: process.env.ALIYUN_SMS_TEMPLATE_REGISTRATION || '',
    passwordReset: process.env.ALIYUN_SMS_TEMPLATE_PASSWORD_RESET || '',
  },
  endpoint: 'https://dysmsapi.aliyuncs.com',
};

// 验证码目的类型与模板代码的映射
const purposeToTemplateCodeKey: Record<VerificationPurpose, keyof typeof smsConfig.templateCode> = {
  'registration': 'registration',
  'password_reset': 'passwordReset'
};

class SmsService {
  // 生成随机验证码
  static generateVerificationCode(length: number = 6): string {
    // 生成指定长度的随机数字
    return Math.random().toString().substring(2, 2 + length);
  }

  // 保存验证码到数据库
  static async saveVerificationCode(
    phone: string,
    code: string,
    purpose: VerificationPurpose,
    expiresInMinutes: number = 5
  ): Promise<number> {
    try {
      // 计算过期时间
      const expiresAt = new Date();
      expiresAt.setMinutes(expiresAt.getMinutes() + expiresInMinutes);

      // 将验证码保存到数据库
      const [result] = await pool.execute(
        `INSERT INTO verification_codes 
         (phone, code, purpose, expires_at, is_used) 
         VALUES (?, ?, ?, ?, ?)`,
        [phone, code, purpose, expiresAt, false]
      );

      return (result as ResultSetHeader).insertId;
    } catch (error) {
      console.error('保存验证码失败:', error);
      throw error;
    }
  }

  // 验证验证码
  static async verifyCode(
    phone: string,
    code: string,
    purpose: VerificationPurpose
  ): Promise<boolean> {
    try {
      // 查询未使用且未过期的验证码
      const [rows] = await pool.execute(
        `SELECT * FROM verification_codes 
         WHERE phone = ? 
         AND code = ? 
         AND purpose = ? 
         AND is_used = FALSE 
         AND expires_at > NOW()
         ORDER BY created_at DESC
         LIMIT 1`,
        [phone, code, purpose]
      );

      const codes = rows as RowDataPacket[];
      if (codes.length === 0) {
        return false;
      }

      // 标记验证码为已使用
      await pool.execute(
        `UPDATE verification_codes 
         SET is_used = TRUE 
         WHERE id = ?`,
        [codes[0].id]
      );

      return true;
    } catch (error) {
      console.error('验证码验证失败:', error);
      return false;
    }
  }

  // 发送短信验证码
  static async sendVerificationCode(
    phone: string,
    purpose: VerificationPurpose
  ): Promise<{ success: boolean; message: string; code?: string }> {
    try {
      // 检查是否已经有最近发送的验证码（防止频繁发送）
      const [existingCodes] = await pool.execute(
        `SELECT * FROM verification_codes 
         WHERE phone = ? 
         AND purpose = ? 
         AND is_used = FALSE 
         AND expires_at > NOW()
         AND created_at > DATE_SUB(NOW(), INTERVAL 1 MINUTE)
         ORDER BY created_at DESC
         LIMIT 1`,
        [phone, purpose]
      );

      const codes = existingCodes as RowDataPacket[];
      if (codes.length > 0) {
        return {
          success: false,
          message: '验证码已发送，请稍后再试',
          code: codes[0].code, // 在开发环境中返回验证码，生产环境应移除
        };
      }

      // 生成新的验证码
      const code = this.generateVerificationCode();

      // 保存验证码到数据库
      await this.saveVerificationCode(phone, code, purpose);

      // 如果阿里云短信服务配置不完整，则模拟发送
      if (!smsConfig.accessKeyId || !smsConfig.accessKeySecret) {
        console.log(`模拟发送短信验证码: ${code} 到 ${phone} 用于${purpose}`);
        return {
          success: true,
          message: '验证码发送成功（模拟）',
          code, // 在开发环境中返回验证码，生产环境应移除
        };
      }

      // 调用阿里云短信服务发送验证码
      const templateCodeKey = purposeToTemplateCodeKey[purpose];
      const templateCode = smsConfig.templateCode[templateCodeKey];
      const result = await this.sendSms(phone, code, templateCode);

      if (result.success) {
        return {
          success: true,
          message: '验证码发送成功',
          code: process.env.NODE_ENV === 'development' ? code : undefined, // 在开发环境中返回验证码
        };
      } else {
        return {
          success: false,
          message: result.message,
        };
      }
    } catch (error) {
      console.error('发送验证码失败:', error);
      return {
        success: false,
        message: '发送验证码失败，请稍后再试',
      };
    }
  }

  // 调用阿里云短信服务API
  private static async sendSms(
    phoneNumber: string,
    code: string,
    templateCode: string
  ): Promise<{ success: boolean; message: string }> {
    try {
      // 准备请求参数
      const params = {
        AccessKeyId: smsConfig.accessKeyId,
        Action: 'SendSms',
        Format: 'JSON',
        PhoneNumbers: phoneNumber,
        SignName: smsConfig.signName,
        TemplateCode: templateCode,
        TemplateParam: JSON.stringify({ code }),
        Timestamp: new Date().toISOString(),
        SignatureMethod: 'HMAC-SHA1',
        SignatureVersion: '1.0',
        SignatureNonce: crypto.randomUUID(),
        Version: '2017-05-25',
      };

      // 构建签名
      const signature = this.generateAliyunSignature(params, smsConfig.accessKeySecret);

      // 发送请求
      const response = await axios.get(smsConfig.endpoint, {
        params: {
          ...params,
          Signature: signature,
        },
      });

      if (response.data.Code === 'OK') {
        return {
          success: true,
          message: '短信发送成功',
        };
      } else {
        console.error('阿里云短信发送失败:', response.data);
        return {
          success: false,
          message: `短信发送失败: ${response.data.Message}`,
        };
      }
    } catch (error) {
      console.error('阿里云短信API调用错误:', error);
      return {
        success: false,
        message: '短信服务暂时不可用，请稍后再试',
      };
    }
  }

  // 生成阿里云API签名
  private static generateAliyunSignature(
    params: Record<string, string>,
    accessKeySecret: string
  ): string {
    // 1. 按照参数名称的字母顺序排序
    const sortedKeys = Object.keys(params).sort();
    
    // 2. 构建规范化请求字符串
    const canonicalizedQueryString = sortedKeys
      .map(key => {
        return `${this.percentEncode(key)}=${this.percentEncode(params[key])}`;
      })
      .join('&');
    
    // 3. 构建待签名字符串
    const stringToSign = `GET&${this.percentEncode('/')}&${this.percentEncode(canonicalizedQueryString)}`;
    
    // 4. 计算签名
    const hmac = crypto.createHmac('sha1', `${accessKeySecret}&`);
    hmac.update(stringToSign);
    
    // 5. 返回Base64编码的签名
    return hmac.digest('base64');
  }

  // URL编码（阿里云API要求的特殊编码方式）
  private static percentEncode(str: string): string {
    return encodeURIComponent(str)
      .replace(/\+/g, '%20')
      .replace(/\*/g, '%2A')
      .replace(/%7E/g, '~');
  }
}

export default SmsService;
